# -*- coding: utf-8 -*-
# created on 2016/5/10
import copy

from sympy import sympify

from mathsolver.base import Question, Solution, Problem, known_update
from mathsolver.functions.base.classify import classify, getobj
from mathsolver.functions.base.base import new_latex
from mathsolver.functions.base.objects import (BasePoint, BaseMultiple, BaseGraph, BaseName, BaseVariable, BaseFunc,
                                               BaseFuncName, BaseSinFunc, OptionSelect)
# from mathsolver.base import *
# from mathsolver.functions import *
from mathsolver.read_rules import rulebase_start
import re
from mathsolver.preprocess import Classifier, extract, exact_match, blur_match, flatten, clean_query
from collections import defaultdict, OrderedDict

all_db, all_rules, all_conditions, all_questions = rulebase_start()
all_conditions.update(["OF(eq,图象)"])
all_predicate = {}

type_dict = dict([line.strip("\n").split("\t") for line in open("library/objects.dic")])
same_dict = {}
for line in open("library/same.dic"):
    word, sames = line.strip("\n").split("\t")
    same_dict.update([(same, word) for same in sames.split()])

comple_dict = [("椭圆", "TuoYuan"), ("双曲线", "ShuangQu"), ("圆", "Yuan"), ("抛物线", "PaoWuXian"),
               ("正方体", "ZhengFangTi"), ("球面", "Qiu"), ("正四棱柱", "ZhengSiLengZhu"), ("球", "Qiu"),
               ("区间", "Inter")]


class ValidCheckFail(Exception):
    pass


def no_intermediate(problem):
    for question in problem.questions:
        if isinstance(question, Question):
            return False
        elif question.intermediate:
            return False
    return True


def replace(parse, dictionary):
    if isinstance(parse, str):
        if parse.lower() in dictionary:
            return dictionary[parse.lower()]
        else:
            # 修复前n项这种情况 已知等比数列的公比为2,且前5项和为1,则前10项的和等于(   )
            p = "[A-Za-z0-9_]+"
            m = re.findall(p, parse)
            for tt in m:
                if tt in dictionary:
                    parse = parse.replace(tt, dictionary[tt])
            return parse
    elif isinstance(parse, dict):
        for key in parse:
            if isinstance(parse[key], dict):
                replace(parse[key], dictionary)
            elif isinstance(parse[key], list):
                parse[key] = [replace(s, dictionary) for s in parse[key]]
            elif isinstance(parse[key], str):
                parse[key] = replace(parse[key], dictionary)

        return parse
    elif isinstance(parse, list):
        for i in range(len(parse)):
            parse[i] = replace(parse[i], dictionary)
    else:
        raise ValueError(parse)


def replace_tokens(tokens, dictionary):
    for token in tokens:
        replace(token["main"], dictionary)
        if isinstance(token["main"], str):
            for key, value in dictionary.items():
                if re.search("[a-z]%s" % key, token["main"]) or re.search("%s[0-9]" % key, token["main"]):
                    continue
                token["main"] = token["main"].replace(key, value)
        token["text"] = "-".join([dictionary[wrd] if wrd in dictionary else wrd for wrd in token["text"].split("-")])


def add_type(parse, exprs):
    if isinstance(parse, list):
        if not parse:
            return

        i = 0
        while i < len(parse) - 1:
            current, nextt = parse[i], parse[i + 1]
            i += 1
            if isinstance(current, str) and isinstance(nextt, str):
                if current in type_dict and nextt in exprs:
                    if current == '点' and re.sub('[0-9]+', '', nextt) == 'eq':
                        continue
                    if current == '点' and re.sub('[0-9]+', '', nextt) == 'pointname':
                        continue
                    if current == '曲线' and re.sub('[0-9]+', '', nextt) == 'func':
                        continue
                    if current == '复数' and re.sub('[0-9]+', '', nextt).replace("andequal", "") in ['eq', 'poly', 'eqs']:
                        continue
                    exprs[nextt]["type"] = type_dict[current]

            add_type(current, exprs)

        add_type(parse[-1], exprs)

    elif isinstance(parse, str):
        pass

    elif isinstance(parse, dict):
        for key in parse:
            add_type(parse[key], exprs)

    else:
        raise ValueError(parse)


class Extractor(object):
    def __init__(self):
        self.tuples = []

    def extract(self, token):
        if isinstance(token, list):
            if "偶函数" in token:
                funcs = [tt for tt in token if isinstance(tt, str) and "func" in tt]
                if len(funcs) == 1:
                    self.tuples.append([funcs[0], "偶函数"])
            elif "奇函数" in token:
                funcs = [tt for tt in token if isinstance(tt, str) and "func" in tt]
                if len(funcs) == 1:
                    self.tuples.append([funcs[0], "奇函数"])
            elif "幂函数" in token:
                funcs = [tt for tt in token if isinstance(tt, str) and "func" in tt]
                if len(funcs) == 1:
                    self.tuples.append([funcs[0], "幂函数"])
            elif "正整数" in token:
                funcs = [tt for tt in token if isinstance(tt, str) and "variable" in tt]
                if len(funcs) == 1:
                    self.tuples.append([funcs[0], "正整数"])
            elif "等差数列" in token:
                objs = [tt for tt in token if isinstance(tt, str) and "sequence" in tt]
                if len(objs) == 1:
                    self.tuples.append([objs[0], "等差数列"])
            elif "等比数列" in token:
                objs = [tt for tt in token if isinstance(tt, str) and "sequence" in tt]
                if len(objs) == 1:
                    self.tuples.append([objs[0], "等比数列"])

            for kk in token:
                self.extract(kk)

        elif isinstance(token, dict):
            for kk, v in token.items():
                self.extract(v)


class SolvingEngine(object):
    def __init__(self, db, rules, predicate):
        self.db = db
        self.rule_db = []
        for row in self.db.to_records(index=False):
            _id, question, condition = row
            try:
                self.rule_db.append({"id": _id, "question": extract(question), "condition": extract(condition)})
            except Exception:
                print(question, condition)

        self.rules = rules
        self.remote = ""
        self.depth = 0
        self.conds = []
        self.predicate = predicate
        self.exist_symbols = {}
        self.model = None

    def complement(self, parse, exprs):
        """
        补充一些特殊的名称，如圆、抛物线等等
        已知方程x^{2}+y^{2}-2(t+3)x+2(1-4t^{2})y+16t^{4}+9=0表示一个圆,求t的取值范围
        """
        if isinstance(parse, list):
            for name, obj in comple_dict:
                if name in parse and obj not in str(parse).lower():
                    exist = dict([(re.search("[A-Za-z]+", expr).group(), expr) for expr in exprs])
                    exist = [v for expr, v in exist.items() if expr == obj]
                    if len(exist) == 1:
                        index = parse.index(name)
                        # 规避这种情况：圆x^{2}+y^{2}=50与圆x^{2}+y^{2}-12x-6y+40=0的公共弦长为()
                        tmp_parse = [re.sub('[0-9]+', '', t) for t in parse]
                        flag = False
                        if obj in tmp_parse:
                            obj_index = tmp_parse.index(obj)
                            if obj_index == index + 1:
                                flag = True
                        if not flag:
                            # 已知圆C:x^{2}+y^{2}-4x-6y+12=0,求过点A(3,5)的圆的切线方程.
                            parse.insert(index, exist[0])
                    elif not exist and name != "区间":
                        # 正方体的体积为8,正方体的顶点都在同一球面上，则该球面的表面积为
                        index = max([int(re.findall("[0-9]+", key)[0]) for key in exprs]) + 1
                        try:
                            new_obj, conds = getobj(obj + "Name")("").init(self.exist_symbols)
                            self.conds.extend(conds)
                        except Exception:
                            new_obj = getobj(obj)("").init(self.exist_symbols)

                        obj_name = "%s%s" % (obj, index)
                        exprs[obj_name] = new_obj
                        parse.append(obj_name)
                        # num = len(exprs) + 1
                        # new_name = "%s%d" % (obj, num)
                        # parse.append(new_name)
                        # exprs.update((new_name, ))
                        # parse.append()

            for item in parse:
                self.complement(item, exprs)

        elif isinstance(parse, str):
            pass

        elif isinstance(parse, dict):
            for key in parse:
                self.complement(parse[key], exprs)

        else:
            raise ValueError(parse)

    def preprocess(self, tokens, all_exprs, is_option=False):
        self.conds = []
        local_exprs = OrderedDict()
        all_text = "".join([token["text"] for token in tokens])
        for key in sorted(all_exprs.keys(), key=lambda xx: int(re.search("[0-9]+", xx).group(0))):
            if key in all_text:
                local_exprs[key] = all_exprs[key]

        for token in tokens:
            if isinstance(token["main"], str):
                token["main"] = token["main"].split("-")

        # svos展开
        new_tokens = []
        for token in tokens:
            if "svos" in token["main"]:
                for svo in token["main"]["svos"]:
                    new_tokens.append({"main": svo, "text": token["text"]})
                token["main"].pop("svos")
            new_tokens.append(token)
        tokens = new_tokens

        # 近义词替换
        replace_tokens(tokens, same_dict)
        # for tokens in deep_parse_result["options"]:
        #     if tokens and isinstance(tokens,dict):
        #         replace_tokens(tokens, same_dict)

        # 分段函数: 当0≤x≤1时,f(x)=2x(1-x),
        main = tokens
        new_main = []
        flag = False
        exprs = local_exprs
        for t1, t2 in zip(main, main[1:-1]):
            if isinstance(t1["main"], list) or isinstance(t2["main"], list):
                new_main.append(t1)
                continue

            text1 = flatten.flatten(t1["main"])[0]
            text2 = flatten.flatten(t2["main"])[0]
            if clean_query(text2) in ["func"] and "TP" in t1["main"] and len(t1["main"]) == 1 and text1 in exprs and text2 in exprs:
                index = max([int(re.findall("[0-9]+", key)[0]) for key in exprs]) + 1
                name = "piecewise" + clean_query(text2) + str(index)
                value = [exprs[text1], exprs[text2]]
                exprs[name] = value
                exprs.pop(text1)
                exprs.pop(text2)
                new_main.append({"main": {"S": name, "V": "", "O": ""}, "text": ""})
                flag = True
            elif flag:
                flag = False
            else:
                new_main.append(t1)

        if not flag and len(main) > 1:
            new_main.append(main[-2])

        new_main.append(main[-1])
        tokens = new_main

        # 根据上下文判断公式类型
        exprs = local_exprs
        for key in exprs:
            exprs[key] = {"type": "", "value": exprs[key]}

        for token in tokens:
            add_type(token["main"], exprs)

        # 公式分类
        exprs_dict = {}
        exprs = OrderedDict()
        for key, value in local_exprs.items():
            obj = classify(key, value)
            num = re.findall("[0-9]+", key)[0]
            obj_name = obj.__class__.__name__.replace("Base", "")
            if obj_name == "Multiple":
                obj_name = obj.type

            if "andequal" in key:
                obj_name += "andequal"

            if not re.search("[0-9]+", obj_name):
                obj_name += num

            exprs_dict[key] = obj_name
            exprs[obj_name] = obj

        free_symbols = []
        for v in exprs.values():
            try:
                free_symbols.extend(v.free_symbols())
            except Exception:
                pass

        self.exist_symbols = defaultdict(int)
        for sym in set(free_symbols):
            if "_" not in str(sym):
                self.exist_symbols[str(sym)] = 1
            else:
                item = str(sym).split("_")
                if item[1].isdigit():
                    self.exist_symbols[item[0]] = int(item[1])
        self.exist_symbols["x"] += 1
        self.exist_symbols["y"] += 1

        # 公式名称替换
        local_exprs = exprs
        replace_tokens(tokens, exprs_dict)
        # for tokens in deep_parse_result["options"]:
        #     if tokens and isinstance(tokens,dict):
        #         replace_tokens(tokens, exprs_dict)

        for token in tokens:
            self.complement(token["main"], exprs)

        # 设直线、曲线
        graph_dict = {}
        inner_dict = {}
        index = max([int(re.findall("[0-9]+", key)[0]) for key in exprs]) + 1 if exprs else 0
        knownnames = dict([(value.name, key) for key, value in exprs.items() if isinstance(value, BaseGraph) or (
                isinstance(value, BasePoint) and value.name)])  # （ｌ, zhixian2）

        # 拆分Points等类型
        tmp_exprs = copy.deepcopy(exprs)
        for key, value in exprs.items():
            if isinstance(value, BaseMultiple) and isinstance(value.objs[0], (BasePoint, BaseGraph)):
                for obj in value.objs:
                    # 将多个点拆分存储, eg. 已知点A(1,3),B(4,-1),求向量\\overrightarrow{AB}的单位向量.
                    if obj.name:
                        obj_name = "%s%d" % (obj.__class__.__name__.replace("Base", ""), index)
                        index += 1
                        tmp_exprs.update({obj_name: obj})
                        knownnames[obj.name] = obj_name
        exprs = tmp_exprs

        unknown_names = [(key, value.value) for key, value in exprs.items() if isinstance(value, BaseName) or
                         (isinstance(value, BaseMultiple) and isinstance(value.objs[0], BaseName))]

        for kk, v in unknown_names:
            # 对于一些特殊数学变量，预先设定一个初始值，
            # 如 已知直线l_{1}为曲线y={x^2}+x-2在点(1,0)处的切线,直线l_{2}为曲线y={x^2}+x-2的切线,l_{1}⊥l_{2}.求直线l_{2}的方程. => l_1: y=kx+b
            if isinstance(v, list):
                new_objs = []
                for obj in exprs[kk].objs:
                    if obj.value in knownnames:
                        new_objs.append(exprs[knownnames[obj.value]])
                    elif obj.value in inner_dict:
                        new_objs.append(exprs[inner_dict[obj.value]])
                    else:
                        new_obj, conds = obj.init(self.exist_symbols)
                        self.conds.extend(conds)
                        new_objs.append(new_obj)
                        obj_name = "%s%d" % (new_obj.__class__.__name__.replace("Base", ""), index)
                        index += 1
                        inner_dict[obj.value] = obj_name
                        exprs.update({obj_name: new_obj})

                new_type = new_objs[0].__class__.__name__.replace("Base", "") + "s"
                obj_name = "%s%d" % (new_type, index)
                index += 1
                obj = BaseMultiple({"type": new_type, "objs": new_objs})
                exprs.update({obj_name: obj})
                graph_dict[kk] = obj_name
            elif v in knownnames:
                graph_dict[kk] = knownnames[v]
            elif v in inner_dict:
                graph_dict[kk] = inner_dict[v]
            else:
                obj, conds = exprs[kk].init(self.exist_symbols)
                self.conds.extend(conds)
                obj_name = obj.__class__.__name__.replace("Base", "")

                obj_name = "%s%d" % (obj_name, index)
                index += 1
                inner_dict[v] = obj_name
                exprs.update({obj_name: obj})
                local_exprs.update({obj_name: obj})
                graph_dict[kk] = obj_name

        # variable => 映射
        knownnames = dict([(value.name, key) for key, value in exprs.items() if isinstance(value, BaseGraph)])
        unknown_names = [(key, value.value) for key, value in exprs.items() if isinstance(value, BaseVariable)]
        for kk, v in unknown_names:
            if v in knownnames:
                graph_dict[kk] = knownnames[v]

        # funcname => 映射
        knownnames = dict([(value.name, key) for key, value in exprs.items() if
                           type(value) == BaseFunc or type(value) == BaseSinFunc])
        unknown_names = [(key, value.name) for key, value in exprs.items() if
                         type(value) == BaseFuncName and str(value.var) == "x"]
        for kk, v in unknown_names:
            if v in knownnames:
                graph_dict[kk] = knownnames[v]

        replace_tokens(tokens, exprs_dict)

        # 替换graph_dict, 已知函数f(x)=(x-1)/(x*(x+1)).求f(x)的最值.
        replace_tokens(tokens, graph_dict)

        # 属性提取
        if not is_option:
            new_tokens = []
            for i, token in enumerate(tokens):
                extra = Extractor()
                extra.extract(token["main"])
                if extra.tuples:
                    for s, o in extra.tuples:
                        if isinstance(all_exprs[s], list):
                            n_s = ",".join([new_latex(sympify(item)) for item in all_exprs[s]])
                            new_tokens.append({"main": {'S': {'noun': [s]}, 'O': {'noun': [o]}, 'V': 'IS'},
                                               "text": "已知-%s-是-%s" % (s, o),
                                               "sentence": "已知{%s}是%s" % (n_s, o)})
                        else:
                            new_tokens.append({"main": {'S': {'noun': [s]}, 'O': {'noun': [o]}, 'V': 'IS'},
                                               "text": "已知-%s-是-%s" % (s, o),
                                               "sentence": "已知{%s}是%s" % (new_latex(sympify(all_exprs[s])), o)})
                        if isinstance(token, dict):
                            t_main = token['main']
                            if not (len(t_main) == 1 and len(t_main['PP']) == 1 and 'noun' in t_main['PP'].keys() and len(t_main['PP']['noun']) == 2):
                                token['sentence'] = token['sentence'].replace(o, "")
                                token['text'] = token['text'].replace(o, "")
                                new_tokens.append(token)
                else:
                    new_tokens.append(token)
            tokens = new_tokens

        # 去除无用exprs
        # all_tokens = [token for token in deep_parse_result["main"]] + \
        #               [token for sub in deep_parse_result["subquestions"] for token in sub] + \
        #               [token for opt in deep_parse_result["options"] if opt for token in opt]

        all_text = "".join([token["text"] for token in tokens]) + "".join([str(token["main"]) for token in tokens])
        final_local_exprs = {}
        for key in local_exprs.keys():
            if key not in all_text:
                if key in all_exprs:
                    all_exprs.pop(key)
            else:
                final_local_exprs[key] = local_exprs[key]
        for token in tokens:
            if isinstance(token["main"], list):
                token["main"] = "-".join(token["main"])
        return tokens, local_exprs

    def solving(self, deep_parse_result, verbose=False, dry_run=False, log_model=False, raw=None):
        if raw is None:
            raw = {}
        self.depth = 0
        # self.preprocess(deep_parse_result)

        if raw and self.predicate:
            raw_main = raw["main"]
            select = None
            for i, raw_option in enumerate(raw["options"]):
                raw_option = raw_option
                if raw_option in self.predicate:
                    answer = self.predicate[raw_option]
                    solution = Solution([], [], [])
                    if "错误" in raw_main or "不" in raw_main:
                        if not answer:
                            select = "ABCDEF"[i]
                    elif "正确" in raw_main and answer:
                        select = "ABCDEF"[i]
                    else:
                        deep_parse_result["options"][i] = []

                if select is not None:
                    solution.output = [OptionSelect(select)]
                    solution.steps.append({"labels": "", "steps": [["", "答：%s" % select]]})
                    return solution, [], []

        tokens, exprs = self.preprocess(deep_parse_result["main"], deep_parse_result["exprs"])
        deep_parse_result["main"] = tokens
        solution = None
        flag = False
        try:
            conditions, questions = classifier.process(tokens)
            if dry_run:
                return Solution([], [], []), conditions, questions
            flag = True
            problem = Problem({"conditions": conditions, "questions": questions}, exprs, self.conds,
                              exist_symbols=self.exist_symbols)
            solution = self.basic_solving(problem, verbose, len(problem.conditions) == 0)
        except Exception as e:
            print(e)
            if dry_run:
                raise e

        if deep_parse_result["subquestions"]:
            solution = self.solve_subquestion(deep_parse_result, solution, verbose)

        if not isinstance(solution, Solution) and len(deep_parse_result["options"]) > 0:
            solution = self.solve_options(deep_parse_result, solution, verbose)

        if self.model and not isinstance(solution, Solution) and not flag:
            tokens = self.model.predict(tokens)
            conditions, questions = classifier.process(tokens)
            problem = Problem({"conditions": conditions, "questions": questions}, exprs, self.conds)
            solution = self.basic_solving(problem, verbose, len(problem.conditions) == 0)

        return solution, [], []

    def solve_subquestion(self, deep_parse_result, solution, verbose):
        if isinstance(solution, Solution):
            solution.steps = [{"labels": "", "steps": [["(1)", ""]]}] + solution.steps

        for numq, subq in enumerate(deep_parse_result["subquestions"], 2):
            try:
                tokens, exprs = self.preprocess(subq, deep_parse_result["exprs"])
                conditions, questions = classifier.process(tokens)
                problem = Problem({"conditions": conditions, "questions": questions}, exprs)
                self.depth = 0
                sub_solution = self.basic_solving(problem, False, len(problem.conditions) == 0)
                if isinstance(sub_solution, Solution):
                    sub_solution.steps = [{"labels": "", "steps": [["(%d)" % numq, ""]]}] + sub_solution.steps
                    # log_success(subq)

                if isinstance(sub_solution, Solution):
                    if not solution:
                        solution = sub_solution
                    elif sub_solution:
                        solution += sub_solution
            except Exception as e:
                print(e)
        return solution

    def solve_options(self, deep_parse_result, solution, verbose):
        option_solution = Solution([], [], [])
        all_outputs = []
        for options in deep_parse_result["options"]:
            try:
                tokens, exprs = self.preprocess(options, deep_parse_result["exprs"], is_option=True)
                sub_conditions, sub_questions = classifier.process_options(tokens)
                answer = None
                subproblem = Problem({"questions": sub_questions, "conditions": sub_conditions}, exprs)
                self.depth = 0
                new_solution = self.basic_solving(subproblem, verbose, len(sub_conditions) == 0)
                # if isinstance(new_solution, Solution):
                #     log_success(options)
            except Exception as e:
                print(e)

            if new_solution is not None:
                option_solution += new_solution
                if new_solution.output:
                    answer = [output.value for output in new_solution.output if isinstance(output, BaseVariable)]
                    if answer:
                        answer = all(answer)
                    else:
                        answer = False

            all_outputs.append(answer)

        answers = [i for i, out in enumerate(all_outputs) if out is True]
        if not isinstance(solution, Solution):
            solution = option_solution
            if len(answers) == 0:
                raise ValueError()  # answers = [0]#return "no option correct/wrong", "", ""
            elif len(answers) > 1:
                return "more than one options correct/wrong", "", ""

        if answers:
            option_solution.output = [OptionSelect("ABCDEF"[answers[0]])]
            solution.steps.append({"labels": "", "steps": [["", "答：%s" % "ABCDEF"[answers[0]]]]})

        return solution

    def _search(self, ques, cond):
        inner_search = []
        for rule in self.rule_db:
            if exact_match(extract(ques), rule["question"]) and exact_match(extract(cond), rule["condition"]):
                inner_search.append(rule["id"])

        for rule in self.rule_db:
            if blur_match(extract(ques), rule["question"]) and blur_match(extract(cond), rule["condition"]):
                inner_search.append(rule["id"])

        return inner_search

    def search(self, question, condition):
        question = question.to_query() if question else ""
        condition = condition.to_query() if condition else ""
        rule_ids = []
        if isinstance(condition, list):
            for cond in condition:
                rule_ids = self._search(question, cond)
                if rule_ids:
                    break
        else:
            rule_ids = self._search(question, condition)
        return rule_ids

    def recursive_solving(self, token, problem, verbose):
        steps = token.main.split(";")
        obj_dict = {}
        last_rule = None
        rule_s = None
        for i, step in enumerate(steps):
            if i != len(steps) - 1:
                ruler, obj = step.split("=")
            else:
                ruler, obj = step.split("=")[0], ""

            objs = re.findall("obj[0-9]+", ruler)
            if objs:
                for obj_name in objs:
                    obj_value = obj_dict[obj_name]
                    num = re.search("([0-9]+)", obj_name).group(1)
                    type_name = obj_value.__class__.__name__.replace("base", "").lower() + num
                    problem.exprs[type_name] = obj_value
                    ruler = ruler.replace(obj_name, type_name)

            token.main = ruler
            rule_s = self.simple_solving(token, "", problem, verbose)
            if not rule_s:
                rule_s = self.simple_solving("", token, problem, verbose)

            if rule_s:
                rule = rule_s[0]
                if last_rule:
                    rule.labels = last_rule.labels + rule.labels
                    rule.steps = last_rule.steps + rule.steps
                last_rule = rule
                if obj:
                    obj_dict[obj] = rule.last[0]

                if i != len(steps) - 1:
                    for item in rule.last:
                        if isinstance(item, BaseFunc):
                            known_update(problem.known, item)
            else:
                return

        return rule_s

    def simple_solving(self, question, condition, problem, verbose):
        rule_ids = set(self.search(question, condition))
        rule_s = []
        if len(rule_ids) > 0:
            for i in list(OrderedDict.fromkeys(rule_ids)):
                rule = self.rules[i]
                try:
                    rule.run(question, condition, problem)
                    if verbose:
                        print("success cell function:", ",".join(rule.func), rule.printing())
                    rule_s.append(rule)
                    if condition == '' and question is not None:
                        return rule_s
                except Exception as e:
                    print("failed cell function:", ",".join(rule.func), rule.printing(), e)
        return rule_s

    def basic_solving(self, problem, verbose, question_only):
        self.depth += 1
        if self.depth > 15:
            return None
        elif problem is None:
            return None
        elif len(problem.conditions) == 0 and not question_only and no_intermediate(problem):
            return problem.solution
        elif no_intermediate(problem) and question_only:
            return problem.solution
        elif not problem.conditions and problem.questions and (not isinstance(problem.questions[0], Question)):
            # 若直线l的斜率为-\\sqrt{3},则直线l的倾斜角为()
            return problem.solution
        else:
            pairs = problem.get_pairs()
            for question, condition in pairs:
                if condition == "":
                    problem.deduce()
                if question and ";" in question.main and not condition:
                    rules = self.recursive_solving(question, problem, verbose)
                elif condition and ";" in condition.main and not question:
                    rules = self.recursive_solving(condition, problem, verbose)
                else:
                    rules = self.simple_solving(question, condition, problem, verbose)

                if rules:
                    for rule in rules:
                        new_problem = problem.alter(question, condition, rule)

                        solution = self.basic_solving(new_problem, verbose, question_only)
                        if solution:
                            return solution

                elif verbose:
                    problem.fail_pairs.append((question, condition))
                    question = question.to_query() if question else ""
                    condition = condition.to_query() if condition else ""
                    print("query failed: (%s, %s)" % (question, condition))

        return None


engine = SolvingEngine(all_db, all_rules, all_predicate)
classifier = Classifier(all_conditions, all_questions)

if __name__ == '__main__':
    pass
